/*
 * Hidden Equity LLC
 * Author: Maksym Fedyay, Kyiv, mcsimf@gmail.com
 * Date: 29.02.2012
 */

package com.hiddenequity.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

import android.app.Application;

public class LocationDataProvider {
	
	final public static String LANG_URL = "http://code.google.com/apis/adwords/docs/appendix/languagecodes.csv";
	final public static String WORLD_CITY_URL = "http://code.google.com/apis/adwords/docs/appendix/cities_world.csv";
	final public static String USA_CITY_URL = "http://code.google.com/apis/adwords/docs/appendix/cities_us.csv";
	final public static String PROVINCE_URL = "http://code.google.com/apis/adwords/docs/appendix/provincecodes.csv";
	final public static String COUNTRY_URL = "http://code.google.com/apis/adwords/docs/appendix/countrycodes.csv";

	public static ArrayList<Language> languageList = new ArrayList<Language>();
	public static ArrayList<Country> countryList = new ArrayList<Country>();
	public static ArrayList<City> worldCityList = new ArrayList<City>();
	public static ArrayList<City> usCityList = new ArrayList<City>();
	public static ArrayList<City> cityList = new ArrayList<City>();
	
	public static ArrayList<Province> provinceList = new ArrayList<Province>();
	public static ArrayList<String> metroList = new ArrayList<String>();

	private static final String LANGUAGE_FILE = "language.csv";
	private static final String COUNTRY_FILE = "country.csv";
	private static final String WORLD_CITY_FILE = "worldcity.csv";
	private static final String PROVINCE_FILE = "province.csv";
	private static final String US_CITY_FILE = "uscity.csv";
	
	
	private static Application _application;
	
	
	/*
	 * Get Country criteria Id
	 */
	public static Country getCountryByName(String countryName){
		Country result = null;
		
		if(countryList.isEmpty())
			return result;
		
		for(Country country : countryList){
			if(country.getName().equals(countryName)){
				result = country;
			}	
		}
		
		return result;
	}//getCountryCriteriaId
	
	
	/*
	 * Get Region criteria Id
	 */
	public static Province getProvinceByName(String regionName, String countryCode){
		Province result = null;
		if(provinceList.isEmpty())
			return result;
		
		for(Province province : provinceList){
			if(province.getProvinceName().equals(regionName) && province.getCountryCode().equals(countryCode)){
				result = province;
			}	
		}
		return result;
	}//getRegionCriteriaId
	
	
	/*
	 * Get city criteria Id
	 */
	public static City getCityByName(String cityName, String provinceCode, String countryCode){
		City result = null;
		if(cityList.isEmpty())
			return result;

		for(City city : cityList){
			if(city.getCityName().equals(cityName) 
					&& city.getProvinceCode().equals(provinceCode) 
					&& city.getCountryCode().equals(countryCode)){
				result = city;
			}	
		}
		
		return result;
	}//getCityCriteriaId
	
	
	/*
	 * Get language list
	 */
	public static ArrayList<Language> getLanguageList(Application application){
		if(languageList.isEmpty()){
			_application = application;
			
			if(getLanguageCSVData()){
				
				final File csvFile  = new File(getCacheFolder(), LANGUAGE_FILE);

				BufferedReader br = null;

				try {
					br = new BufferedReader(new FileReader(csvFile));
				}
				catch (IOException e) {
				    //You'll need to add proper error handling here
				}
				
		    	try {
		    		String langName = null;
		    		String langCode = null;
		    		String criteriaId = null;
		    		
		    		String line = "";
		    		//read comma separated file line by line
		    		
		    		while((line = br.readLine()) != null){
		    			StringTokenizer st = new StringTokenizer(line, ",");
		    			
		    			while (st.hasMoreTokens()){
		    				//get next token and store it in the array
		    				if(langName == null){
		    					langName = st.nextToken();
		    				} else if(langCode == null){
		    					langCode = st.nextToken();
		    				} else if(criteriaId == null){
		    					criteriaId = st.nextToken();
		    				}
		    			}
		    			
		    			Language lang = new Language();
		    			lang.setName(langName);
		    			lang.setCode(langCode);
		    			languageList.add(lang);
		    			
		    			langName = null;
		    			langCode = null;
		    			criteriaId = null;
		    		}
		    	} catch (IOException ex) {
		    		// handle exception
		    	}
					
		    	languageList.remove(0);
		    	
		    	return languageList;
				
			} else {
				return languageList;
			}			
		} else {
			return languageList;
		}

	}//getCountryList
	
	
	
	/*
	 * Get country list
	 */
	public static ArrayList<Country> getCountryList(Application application){
		if(countryList.isEmpty()){
			_application = application;
			
			if(getCountryCSVData()){
				
				final File csvFile  = new File(getCacheFolder(), COUNTRY_FILE);

				BufferedReader br = null;

				try {
					br = new BufferedReader(new FileReader(csvFile));
				} catch (IOException e) {
				    //You'll need to add proper error handling here
				}
				
				
		    	try {
		    		String name = null;
		    		String code = null;
		    		String criteriaId = null;
		    		String line = "";
		    		//read comma separated file line by line
		    		while((line = br.readLine()) != null){
		    			CustStringTokenizer st = new CustStringTokenizer(line, ',', '"');
		    			while(true)
		    			{
		    				String token = st.nextToken();
		    				if(token == null)
		    					break;
		    				
		    				if(name == null){
		    					name = token.trim();
		    				} else if(code == null){
		    					code = token.trim();
		    				} else if(criteriaId == null){
		    					criteriaId = token.trim();
		    				}
		    			}

		    			Country country = new Country();
		    			country.setName(name);
		    			country.setCode(code);
		    			country.setCriteriaId(criteriaId);
		    			countryList.add(country);
		    			name = null;
		    			code = null;
		    			criteriaId = null;
		    		}

		    	} catch (IOException ex) {
		    		// handle exception
		    	} 
		    	
		    	countryList.remove(0);
		    	
		    	return countryList;
		    	
			} else {
				return countryList;
			}						
		} else {
			return countryList;
		}
	}//getCountryList
	
	
	
	/*
	 * Get world cities list
	 */
	public static ArrayList<City> getWorldCityList(Application application){
		if(worldCityList.isEmpty()){
			_application = application;
			
			if(getWorldCityCSVData()){
				
				final File csvFile  = new File(getCacheFolder(), WORLD_CITY_FILE);

				BufferedReader br = null;

				try {
					br = new BufferedReader(new FileReader(csvFile));
				} catch (IOException e) {
				    //You'll need to add proper error handling here
				}
				
		    	try {
		    		String countryName = null;
		    		String cityName = null;
		    		String provinceCode = null;
		    		String countryCode = null;
		    		String criteriaId = null;
		    		String line = "";
		    		//read comma separated file line by line
		    		while((line = br.readLine()) != null){
		    			StringTokenizer st = new StringTokenizer(line, ",");
		    			
		    			while (st.hasMoreTokens()){
		    				//get next token and store it in the array
		    				if(countryName == null){
		    					countryName = st.nextToken();
		    				} else if(cityName == null){
		    					cityName = st.nextToken();
		    				} else if(criteriaId == null){
		    					criteriaId = st.nextToken();
		    				} else if(provinceCode == null){
		    					provinceCode = st.nextToken();
		    				} else if(countryCode == null){
		    					countryCode = st.nextToken();
		    				}
		    			}
		    			
		    			City city = new City();
		    			
		    			city.setCityName(cityName);
		    			city.setProvinceCode(provinceCode);
		    			city.setCountryCode(countryCode);
		    			city.setCountryName(countryName);
		    			city.setCriteriaId(criteriaId);
		    			city.setProvinceName(provinceCodeToName.get(provinceCode));
		    			worldCityList.add(city);
		    			
		    			cityName = null;
		    			provinceCode = null;
		    			countryCode = null;
		    			countryName = null;
		    			criteriaId = null;
		    		}
		    		
		    		
		    		provinceCodeToName.clear();
		    	} catch (IOException ex) {
		    		// handle exception
		    	} 
					
		    	worldCityList.remove(0);
		    	
		    	return worldCityList;
				
			} else {
				return worldCityList;
			}						
		} else {
			return worldCityList;	
		}
	}//getCityList
	
	

	/*
	 * Get us cities list
	 */
	public static ArrayList<City> getUSCityList(Application application){
		if(usCityList.isEmpty()){
			_application = application;
			
			if(getUSCityCSVData()){
				
				final File csvFile  = new File(getCacheFolder(), US_CITY_FILE);

				BufferedReader br = null;

				try {
					br = new BufferedReader(new FileReader(csvFile));
				} catch (IOException e) {
				    //You'll need to add proper error handling here
				}

				try {
		    		String provinceName = null;
		    		String cityName = null;
		    		String metroName = null;
		    		String metroCode = null;
		    		String provinceCode = null;
		    		String criteriaId = null;
		    		
		    		String countryCode = "US";
		    		String countryName = "United States";
		    		
		    		String line = "";
		    		//read comma separated file line by line
		    		while((line = br.readLine()) != null){
		    			CustStringTokenizer st = new CustStringTokenizer(line, ',', '"');
		    			
		    			while (true){
		    				
		    				String token = st.nextToken();
		    				if(token == null)
		    					break;	
		    				
		    				//get next token and store it in the array
		    				if(provinceName == null){
		    					provinceName = token.trim();
		    				} else if(cityName == null){
		    					cityName = token.trim();		    					
		    				} else if(criteriaId == null){
		    					criteriaId = token.trim();
		    				} else if(metroName == null){
		    					metroName = token.trim();
		    				} else if(metroCode == null){
		    					metroCode = token.trim();
		    				} else if(provinceCode == null){
		    					provinceCode = token.trim();
		    				}
		    			}
		    			
	    				City city = new City();
	    			
	    				city.setCityName(cityName);
	    				city.setProvinceCode(provinceCode);
	    				city.setProvinceName(provinceName);
	    				city.setCountryCode(countryCode);
	    				city.setCountryName(countryName);
	    				city.setCriteriaId(criteriaId);
	    				city.setMetroName(metroName);
	    				city.setMetroCode(metroCode);
	    			
	    				usCityList.add(city);
	    			
	    				cityName = null;
	    				provinceCode = null;
	    				provinceName = null;
	    				metroName = null;
	    				metroCode = null;
	    				criteriaId = null;
	    			}
		    		
		    	} catch (IOException ex) {
		    		// handle exception
		    	} 
				
				usCityList.remove(0);
				
		    	return usCityList;
				
			} else {
				return usCityList;
			}				
		} else {
			return usCityList;	
		}
	}//getCityList
	
	
	
	/*
	 * Unite world and us city list
	 */
	public static ArrayList<City> getCityList(Application application){
		if(cityList.isEmpty()){
			getUSCityList(application);
			getWorldCityList(application);
			cityList.addAll(worldCityList);
			cityList.addAll(usCityList);
			worldCityList.clear();
			usCityList.clear();	
			return cityList;
		} else {
			return cityList;
		}
	}
	
	
	
	/*
	 * Get province list
	 */
	private static Map<String, String> provinceCodeToName = new HashMap<String, String>();
	
	public static ArrayList<Province> getProvinceList(Application application){
		if(provinceList.isEmpty()){
			_application = application;
			
			if(getProvinceCSVData()){
				
				final File csvFile  = new File(getCacheFolder(), PROVINCE_FILE);

				BufferedReader br = null;

				try {
					br = new BufferedReader(new FileReader(csvFile));
				} catch (IOException e) {
				    //You'll need to add proper error handling here
				}
				
				
		    	try {
		    		String provincecName = null;
		    		String provincecCode = null;
		    		String countryCode = null;
		    		String countryName = null;
		    		String criteriaId = null;
		    		String line = "";
		    		//read comma separated file line by line
		    		while((line = br.readLine()) != null){
		    			CustStringTokenizer st = new CustStringTokenizer(line, ',', '"');
		    			while(true)
		    			{
		    				String token = st.nextToken();
		    				if(token == null)
		    					break;
		    				
		    				if(provincecName == null){
		    					provincecName = token.trim();
		    				} else if(provincecCode == null){
		    					provincecCode = token.trim();
		    				} else if(criteriaId == null){
		    					criteriaId = token.trim();
		    				} else if(countryCode == null){
		    					countryCode = token.trim();
		    				} else if(countryName == null){
		    					countryName = token.trim();
		    				}
		    			}
		    			
		    			Province province = new Province();
		    			
		    			province.setProvinceName(provincecName);
		    			province.setProvinceCode(provincecCode);
		    			province.setCountryCode(countryCode);
		    			province.setCountryName(countryName);
		    			province.setCriteriaId(criteriaId);
		    			
		    			provinceCodeToName.put(provincecCode, provincecName);
		    			
		    			provinceList.add(province);
		    			
		    			provincecName = null;
		    			provincecCode = null;
		    			countryCode = null;
		    			countryName = null;	
		    			criteriaId = null;
		    		}

		    	} catch (IOException ex) {
		    		// handle exception
		    	} 
					
		    	return provinceList;
				
			} else {
				return provinceList;
			}						
		} else {
			return provinceList;
		}

	}//getProvinceList
	
	
	
	/*
	 * Get metro list
	 */
	public static ArrayList<String> getMetroList(){
		if(metroList.isEmpty()){
			
		}
		return null;
	}
	

	/*
	 * Get world city csv file
	 */
	private static boolean getProvinceCSVData(){
		boolean result = true;
		try {
			getCSVData(PROVINCE_URL, PROVINCE_FILE);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			result = false;
		}
		
		return result;
	}
	
	
	/*
	 * Get world city csv file
	 */
	private static boolean getWorldCityCSVData(){
		boolean result = true;
		try {
			getCSVData(WORLD_CITY_URL, WORLD_CITY_FILE);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			result = false;
		}
		
		return result;
	}

	
	/*
	 * Get world city csv file
	 */
	private static boolean getUSCityCSVData(){
		boolean result = true;
		try {
			getCSVData(USA_CITY_URL, US_CITY_FILE);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			result = false;
		}
		
		return result;
	}
	
	
	
	/*
	 * Get language csv file
	 */
	private static boolean getLanguageCSVData(){
		boolean result = true;
		try {
			getCSVData(LANG_URL, LANGUAGE_FILE);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			result = false;
		}
		
		return result;
	}
	
	
	/*
	 * Get country CSV Data
	 */
	private static boolean getCountryCSVData(){
		boolean result = true;
		try {
			getCSVData(COUNTRY_URL, COUNTRY_FILE);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			result = false;
		}
		return result;
	}
	
	
	
	/*
	 * Download content
	 */
	private static void getCSVData(String url, String fileName)
			throws IOException {
		
		final File csvFile  = new File(getCacheFolder(), fileName);
		
		if(!csvFile.exists()){
			URL fileUrl = new URL(url);
			HttpURLConnection httpConnection = null;
			httpConnection = (HttpURLConnection) fileUrl.openConnection();
			httpConnection.setRequestMethod("GET");
			httpConnection.setDoOutput(true);
			httpConnection.connect();
			InputStream inputStream = null;
			inputStream = httpConnection.getInputStream();

			final File cacheDir = new File(getCacheFolder());
			// Copy data
			try {
				final File outputFile = new File(cacheDir, fileName);
				copyStreams(inputStream, new FileOutputStream(outputFile));
			} catch (Exception e) {
				e.printStackTrace();
			}			
		}
	}// downloadContentFromUrl
    
    
	
	/*
	 * Copy stream
	 */
	private static void copyStreams(InputStream input, OutputStream output) throws IOException {
		byte[] buffer = new byte[1024];
	    int len = 0;
	    while ( (len = input.read(buffer)) > 0 ) {
	    	output.write(buffer, 0, len);
		}
	}//copyStreams    
    
	
	
    /*
     * Get folder of application
     */
	private static String getCacheFolder() {
		return _application.getFilesDir().getAbsolutePath();
	}//getCacheFolder
	
	
	
}
